<?php

declare(strict_types=1);

//申请应用配置
$domain = 'http://127.0.0.1:8080/';
$config = [
    //test  app_id c_secret
    'app_id'   => '8f41e8aaa0715450ea866633f66357f1491a66e9',
    'c_secret' => 'Y3oT-olhFSrH-P2U9rTUIVAuYBTCNj9i',
];

//方案列表
function programmeList(): R
{
    return request('GET', '/v1/programme/programme-list', []);
}

//方案详情
function programmeDetail(string $pId): R
{
    $params = [
        'p_id' => $pId,
    ];
    $path   = '/v1/programme/programme-detail?'.http_build_query($params);

    return request('GET', $path, $params);
}

//方案下单校验
function programmeCheck(string $pId): R
{
    $params = [
        'p_id' => $pId,
    ];
    $path   = '/v1/programme/programme-check?'.http_build_query($params);

    return request('GET', $path, $params);
}

//方案确认下单
function programmeSubmit(string $pId): R
{
    $params = [
        'p_id' => $pId,
    ];
    $path   = '/v1/programme/programme-submit?'.http_build_query($params);

    return request('GET', $path, $params);
}

//创建礼包方案（免登陆）
function programmeAdd(): R
{
    $body = [
        'cu_id'         => 1,
        'cu_name'       => 'SK',
        'customer_id'   => 1,
        'customer_name' => 'CSK',
    ];

    return request('POST', '/v1/programme/programme-add', $body);
}

//渠道创建C端用户
function authorizeUser(): R
{
    $body = [
        'user_id' => 1,
        'mobile'  => 'm',
    ];

    return request('POST', '/v1/user/authorize-user', $body);
}

//支付成功异步通知
function payNotify(): R
{
    $body = [
        'user_id'  => 1,
        'trade_no' => 1,
        'success'  => 'm',
    ];

    return request('POST', '/v1/user/authorize-user', $body);
}

/**
 * ---------------------------------------------------------------------
 *
 * request 相关的操作
 *
 * ---------------------------------------------------------------------
 */
function request(string $method, string $url, array $params): R
{
    global $domain;

    $time    = time();
    $headers = headers(['time: '.$time, 'sign: '.generateSign($params, $time)]);
    $url     = $domain.$url;

    return doRequest($method, $url, $headers, $params);
}


function headers(array $headers = []): array
{
    global $config;

    return array_merge(['Content-type: application/x-www-form-urlencoded', 'appid: '.$config['app_id']], $headers);
}

//所有的请求参数的值加上 c_secret  作为字符串按照键名从小到大排序后用&和=链接后做sha1混淆加密生成签名
function generateSign(array $params, int $time): string
{
    global $config;

    $data = $params + ['c_secret' => $config['c_secret'], 'time' => $time];
    ksort($data, SORT_STRING);

    return sha1(http_build_query($data));
}

function doRequest(string $method, string $url, array $header = [], array $param = []): R
{
    $result = curl($url, $method, $header, $param);

    return new R($result);
}

function curl(string $url, string $method = 'get', array $header = [], array $param = []): array
{
    $val = strtolower($method) === 'get' ? 0 : 1;

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

    curl_setopt($ch, CURLOPT_HTTPHEADER, $header);

    if ($param and $val === 1) {
        curl_setopt($ch, CURLOPT_POST, $val);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($param));
    }

    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $f = 0);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $f);

    try {
        if (!$result = json_decode((string) curl_exec($ch), true)) {
            throw new \InvalidArgumentException('请正确配置你的url ['.$url.'] or 启动你的渠道服务');
        }

        return $result;
    } finally {
        curl_close($ch);
    }
}

/**
 * @property-read int status
 * @property-read string message
 * @property-read mixed data
 */
class R
{
    protected $data;

    public function __construct(array $data)
    {
        $this->data = $data;
    }

    public function __get($name)
    {
        return $this->data[$name] ?? '';
    }

    public function ok(): bool
    {
        return $this->status === 200;
    }

    public function dp()
    {
        var_dump($this->data);
    }

    public function toArray(): array
    {
        return $this->data;
    }
}